package com.evil.common.core.util;

import cn.hutool.core.convert.Convert;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

/**
 * 客户端工具类
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
public class ServletUtils {

    /**
     * 获取String参数
     */
    public static String getParameter(String name) {
        return getRequest().getParameter(name);
    }

    /**
     * 获取String参数
     */
    public static String getParameter(String name, String defaultValue) {
        return Convert.toStr(getRequest().getParameter(name), defaultValue);
    }

    /**
     * 获取Integer参数
     */
    public static Integer getParameterToInt(String name) {
        return Convert.toInt(getRequest().getParameter(name));
    }

    /**
     * 获取Integer参数
     */
    public static Integer getParameterToInt(String name, Integer defaultValue) {
        return Convert.toInt(getRequest().getParameter(name), defaultValue);
    }

    /**
     * 获取request
     */
    public static HttpServletRequest getRequest() {
        return getRequestAttributes().getRequest();
    }

    /**
     * 获取response
     */
    public static HttpServletResponse getResponse() {
        return getRequestAttributes().getResponse();
    }

    /**
     * 获取session
     */
    public static HttpSession getSession() {
        return getRequest().getSession();
    }

    public static ServletRequestAttributes getRequestAttributes() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }

    /**
     * 将字符串渲染到客户端
     *
     * @param response 渲染对象
     * @param string   待渲染的字符串
     * @return null
     */
    public static String renderString(HttpServletResponse response, String string) {
        try {
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.getWriter().print(string);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 是否是Ajax异步请求
     *
     * @param request request
     */
    public static boolean isAjaxRequest(HttpServletRequest request) {
        String accept = request.getHeader("accept");
        if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) {
            return true;
        }

        String xRequestedWith = request.getHeader("X-Requested-With");
        return xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest");
    }

    public static String getRequestBody(HttpServletRequest request) {
        String requestBody = "";
        if (isFileForRequest(request) || !isJsonForRequest(request)) {
            return requestBody;
        }

        try {
            requestBody = streamToString(request.getInputStream());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return requestBody;
    }

    /**
     * 获取当前请求头
     *
     * @return Map
     */
    public static Map<String, Object> getHeaderMap() {
        HashMap<String, Object> headerMap = new HashMap<>();
        ServletUtils.getHeaders(ServletUtils.getRequest(), headerMap::put);
        return headerMap;
    }

    /**
     * 获取请求头
     *
     * @param request request
     * @param handle  handle
     */
    public static void getHeaders(HttpServletRequest request, BiConsumer<String, String> handle) {
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                if (name == null) {
                    continue;
                }
                // 该类型不可以覆盖
                if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name)) {
                    continue;
                }
                // 跳过 content-length
                if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)){
                    continue;
                }
                String value = request.getHeader(name);
                handle.accept(name, value);
            }
        }
    }

    /**
     * 判断本次请求的数据类型是否为json
     *
     * @param request request
     * @return boolean
     */
    private static boolean isJsonForRequest(HttpServletRequest request) {
        if (request.getContentType() != null) {
            return request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE) ||
                    request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE);
        }
        return false;
    }

    /**
     * 判断本次请求的数据类型是否为文件
     *
     * @param request request
     * @return boolean
     */
    public static boolean isFileForRequest(HttpServletRequest request) {
        if (request.getContentType() != null) {
            return request.getContentType().startsWith("multipart");
        }
        return false;
    }

    /**
     * @param inputStream inputStream
     * @return 字符串转换之后的
     */
    public static String streamToString(InputStream inputStream) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            StringBuilder builder = new StringBuilder();
            String output;
            while ((output = br.readLine()) != null) {
                builder.append(output);
            }
            return builder.toString();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return "";
    }

    /**
     * @param inputStream inputStream
     * @return byte[]
     */
    public static byte[] streamToBytes(ServletInputStream inputStream) {
        return streamToString(inputStream).getBytes(StandardCharsets.UTF_8);
    }
}
